package com.jaws.core.common.log;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.Data;

import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.MethodParameterScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jaws.core.common.util.ClassScaner;

/**
 * 日志扫描器
 * 
 * @author maojian
 * @date 2017-09-28 16:30:40
 * @since v1.0.0
 */
@Data
public class LogScanner implements CommandLineRunner {

	private final String separatorPattern = ",|;|\\|";

	private static final String SWITCH_ON = "ON";

	private String sensLogPath;

	private String sensLogSwitch;

	private String annoPath = "com.jaws.core.common.validator";

	/**
	 * 通过扫描，获取反射对象
	 *
	 * @param packName
	 * @return
	 */
	private Reflections getReflection(String packName) {
		Iterable<String> paths = Splitter.onPattern(separatorPattern).split(packName);
		FilterBuilder filter = new FilterBuilder();
		filter.includePackage(annoPath);
		List<URL> urls = new ArrayList<URL>();
		for (String path : paths) {
			filter.includePackage(path);
			urls.addAll(ClasspathHelper.forPackage(path));
		}
		Reflections reflections = new Reflections(new ConfigurationBuilder()
				.filterInputsBy(filter)
				.setScanners(new SubTypesScanner().filterResultsBy(filter), new TypeAnnotationsScanner().filterResultsBy(filter), new FieldAnnotationsScanner().filterResultsBy(filter),
						new MethodAnnotationsScanner().filterResultsBy(filter), new MethodParameterScanner()).setUrls(urls));
		return reflections;
	}

	@Override
	public void run(String... args) throws Exception {
		if (sensLogSwitch.equalsIgnoreCase(SWITCH_ON) && StringUtils.isNotBlank(sensLogPath)) {
			Log.isSansInfoCrytoEnable = true;
			Reflections reflections = getReflection(sensLogPath);
			TypeFilter filter = new TypeFilter() {
				@Override
				public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
					return metadataReader.getClassMetadata().isAnnotation();
				}
			};
			List<TypeFilter> includeFilter = Lists.newArrayList(filter);
			Log.annotationClassed = new ClassScaner(includeFilter, null).doScan(annoPath);
			for (Class anno : Log.annotationClassed) {
				Set<Field> fields = reflections.getFieldsAnnotatedWith(anno);
				for (Field f : fields) {
					if (Log.sensClassMap.containsKey(f.getDeclaringClass())) {
						Log.sensClassMap.get(f.getDeclaringClass()).put(f.getName(), anno);
					} else {
						Map<String, Class<?>> sm = Maps.newHashMap();
						sm.put(f.getName(), anno);
						Log.sensClassMap.put(f.getDeclaringClass(), sm);
					}

				}
			}
		}

	}

}
